//*****************************************************************
// IOThreadGroup.h
//
//  Created on: Jan 21, 2012
//      Author: Christopher Wood
//              Robert Livosi
//
//  $Id: IOThreadGroup.h 24 2012-01-28 02:54:38Z caw4567@gmail.com $
//*****************************************************************

#ifndef ANALOGSIGNALTHREADGROUP_H_
#define ANALOGSIGNALTHREADGROUP_H_

#include "Project2.h"
#include "TransformThread.h"
#include "ControlThread.h"

// Resolve cyclic depedency
class TransformThread;
class ControlThread;

/**
 * This class is responsible for handling the analog input and output
 * routines for the PID controller. It groups together two independent
 * input and output threads so as to isolate the I/O functionality
 * from the rest of the controller.
 */
class IOThreadGroup
{
public:
	/**
	 * Default constructor for the IOThreadGroup that initializes the
	 * hardware necessary to perform analog I/O.
	 */
	IOThreadGroup();

	/**
	 * Default destructor (does nothing).
	 */
	virtual ~IOThreadGroup();

	/**
	 * Perform an A/D conversion.
	 */
	void performADConversion(void);

	/**
	 * Read the A/D data from the hardware.
	 *
	 * @return analog signal value.
	 */
	int16_t readADData(void);

	/**
	 * Convert an analog signal value to its floating point alternative.
	 *
	 * @param adBoardData - the analog signal value.
	 * @return the converted floating point value.
	 */
	float convertAnalogToFloat(int16_t adBoardData);

	/**
	 * Convert a floating point voltage level to an analog signal.
	 *
	 * @param adData - the desired analog voltage.
	 * @return the converted voltage level.
	 */
	int16_t convertFloatToAnalog(float adData);

	/**
	 * Determine if the analog input thread is still alive.
	 *
	 * @return true if alive, false otherwise.
	 */
	bool isInputThreadAlive();

	/**
	 * Determine if the analog output thread is still alive.
	 *
	 * @return true if alive, false otherwise.
	 */
	bool isOutputThreadAlive();

	/**
	 * Set the state of the analog input thread.
	 *
	 * @param alive - new thread state.
	 */
	void setInputThreadState(bool alive);

	/**
	 * Set the state of the analog output thread.
	 *
	 * @param alive - new thread state.
	 */
	void setOutputThreadState(bool alive);

	/**
	 * Release the input thread from its semaphore.
	 */
	void releaseInputThread();

	/**
	 * Release the output thread from its semaphore.
	 */
	void releaseOutputThread();

	/**
	 * Indicate that a new A/D sample should be performed.
	 */
	void signalInputData();

	/**
	 * Get a pointer to the semaphore controlling the intput thread.
	 *
	 * @return pointer to input task semaphore.
	 */
	sem_t* getInputThreadSem();

	/**
	 * Get a pointer to the semaphore controlling the output thread.
	 *
	 * @return pointer to output task semaphore.
	 */
	sem_t* getOutputThreadSem();

	/**
	 * Assign a transform thread to this I/O group.
	 *
	 * @param tThread - pointer to the transform thread.
	 */
	void assignTransform(TransformThread* tThread);

	/**
	 * Assign a user control thread to this I/O group.
	 *
	 * @param cThread - pointer to the user control thread.
	 */
	void assignControl(ControlThread* cThread);

	/**
	 * Retrieve the next value from the transform thread's list.
	 *
	 * @return most recent input value.
	 */
	float getInputValue();

	/**
	 * Retrieve the next value from the output thread's list.
	 *
	 * @return most recent output value.
	 */
	float getOutputValue();

	/**
	 * Add a converted value to the output thread's list.
	 *
	 * @val - new value to add to the output list.
	 */
	void setOutputValue(float val);

	/**
	 * Add an input value to the transform object's list.
	 *
	 * @val - new value to add to the input list.
	 */
	void setInputValue(float val);

	/**
	 * Retrieve the current transformer object used by the controller.
	 *
	 * @return a pointer to the current TransformThread object.
	 */
	TransformThread* getTransformer();

	/**
	 * Start the input thread.
	 */
	void runInputThread();

	/**
	 * Start the output thread.
	 */
	void runOutputThread();

	// Length of control data buffers
	static const uint8_t BUFFER_SIZE = 32;

	// DAC configuration registers
	static const uint16_t DAC_BASE = 0x280;
	static const uint16_t DAC_ANALOG_INPUT_STATUS = 0x283;
	static const uint16_t DAC_LSB = 0x286;
	static const uint16_t DAC_MSB_Channel = 0x287;
	static const uint16_t DIO_CTRL_ADDRESS = 0x28B;
	static const uint16_t BASE_ADDRESS = 0x280;
	static const uint16_t AD_RANGE = 32768;
	static const uint16_t WAIT_DAC = 0x10;  // bit-4 of base+3 to wait for DAC to update

private:
	// DAC configuration registers
	static const uint8_t MIN_VOLTAGE_VAL = -5;
	static const uint8_t MAX_VOLTAGE_VAL = 5;

	// ADC configuration registers
	static const uint32_t LSB_BASE_ADDRESS = BASE_ADDRESS;
	static const uint32_t MSB_BASE_ADDRESS = BASE_ADDRESS + 0x01;
	static const uint8_t BASE_OUTPUT_VAL = 0x80;
	static const uint32_t AD_CHANNEL_ADDRESS = BASE_ADDRESS + 0x02;
	static const uint8_t AD_CHANNEL_VAL = 0x44;
	static const uint32_t ANALOG_INPUT_STATUS_ADDRESS = BASE_ADDRESS + 0x03;
	static const uint8_t ANALOG_INPUT_STATUS_VAL = 0x00;
	static const uint8_t ANALOG_INPUT_WAIT_BIT = 0b00100000;
	static const uint8_t INPUT_RANGE = 10;

	// Length of all ports (just a single bit for now)
	static const uint8_t PORT_LENGTH = 0x01;

	// Boolean flags controlling the input/output thread execution
	volatile bool inputThreadAlive;
	volatile bool outputThreadAlive;

	// Binary semaphores used to control the input/output processes.
	sem_t inputThreadSem;
	sem_t outputThreadSem;

	// Private data handles that are shared by various routines inside the converter
	uintptr_t lsbHandle;
	uintptr_t msbHandle;
	uintptr_t adChannelHandle;
	uintptr_t analogInputStatusHandle;
	uintptr_t dioControlHandle;
	uintptr_t ainteHandle;// = mmap_device_io(PORT_LENGTH, ANALOG_INPUT_STATUS_ADDRESS + 1);
	uintptr_t fifoHandle;// = mmap_device_io(PORT_LENGTH, ANALOG_INPUT_STATUS_ADDRESS + 2);
	uintptr_t basep1Handle;// = mmap_device_io(PORT_LENGTH, 0x280);

	// Input and output thread identifiers
	pthread_t inputThreadID;
	pthread_t outputThreadID;

	// Private, shared buffers used during control processing
	float inputBuffer[BUFFER_SIZE];
	float outputBuffer[BUFFER_SIZE];

	// Buffer indices used by input/output threads during processing
	uint8_t inputPutIndex;
	uint8_t inputGetIndex;
	uint8_t outputPutIndex;
	uint8_t outputGetIndex;

	// Pointers to the transform/control thread pairs
	ControlThread* controlThread;
	TransformThread* transformThread;
};

#endif /* ANALOGSIGNALTHREADGROUP_H_ */
